package jdk8.stream;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.DoubleSummaryStatistics;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.junit.Test;

import beans.Employee;
import beans.Employee.Status;

public class TerminatingOperation2 {

	List<Employee> emps = Arrays.asList(//
			new Employee(102, "李四", 79, 6666.66, Status.BUSY), //
			new Employee(101, "张三", 18, 9999.99, Status.FREE), //
			new Employee(103, "王五", 28, 3333.33, Status.VOCATION), //
			new Employee(104, "赵六", 8, 7777.77, Status.BUSY), //
			new Employee(104, "赵六", 8, 7777.77, Status.FREE), //
			new Employee(104, "赵六", 8, 7777.77, Status.FREE), //
			new Employee(105, "田七", 38, 5555.55, Status.BUSY)//
	);

	// 3. 终止操作
	/*
		归约
		reduce(T identity, BinaryOperator) / reduce(BinaryOperator) ——可以将流中元素反复结合起来，得到一个值。
	 */
	@Test
	public void test1() {
		List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

		Integer sum = list.stream().reduce(0, (x, y) -> x + y);

		System.out.println(sum);

		System.out.println("----------------------------------------");

		Optional<Double> op = emps.stream().map(Employee::getSalary).reduce(Double::sum);

		System.out.println(op.get());
	}

	// 需求：搜索名字中 “六” 出现的次数
	@Test
	public void test2() {
		Optional<Integer> sum = emps.stream().map(Employee::getName).flatMap(this::filterCharacter)
				.map((ch) -> {
					if (ch.equals('六'))
						return 1;
					else
						return 0;
				}).reduce(Integer::sum);

		System.out.println(sum.get());
	}
	
	public  Stream<Character> filterCharacter(String str) {
		List<Character> list = new ArrayList<>();

		for (Character ch : str.toCharArray()) {
			list.add(ch);
		}

		return list.stream();
	}

	// collect——将流转换为其他形式。接收一个 Collector接口的实现，用于给Stream中元素做汇总的方法
	@Test
	public void test3() {
		List<String> list = emps.stream().map(Employee::getName).collect(Collectors.toList());
		list.forEach(System.out::println);

		System.out.println("----------------------------------");

		Set<String> set = emps.stream().map(Employee::getName).collect(Collectors.toSet());
		set.forEach(System.out::println);

		System.out.println("----------------------------------");

		HashSet<String> hs = emps.stream().map(Employee::getName).collect(Collectors.toCollection(HashSet::new));
		hs.forEach(System.out::println);
	}

	@Test
	public void test4() {
		// 最大值
		Optional<Double> max = emps.stream().map(Employee::getSalary).collect(Collectors.maxBy(Double::compare));
		System.out.println(max.get());
		
		// 最小值
		Optional<Employee> op = emps.stream().collect(Collectors.minBy((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary())));
		System.out.println(op.get());
		
		// 求和
		Double sum = emps.stream().collect(Collectors.summingDouble(Employee::getSalary));
		System.out.println(sum);
		
		//求平均值
		Double avg = emps.stream().collect(Collectors.averagingDouble(Employee::getSalary));
		System.out.println(avg);

		// 总条数
		Long count = emps.stream().collect(Collectors.counting());
		System.out.println(count);

		System.out.println("--------------------------------------------");
		
		// summarizingDouble 返回结果值的汇总统计信息。
		//DoubleSummaryStatistics{count=7, sum=48888.840000, min=3333.330000, average=6984.120000, max=9999.990000}
		DoubleSummaryStatistics dss = emps.stream().collect(Collectors.summarizingDouble(Employee::getSalary));
		System.out.println(dss.getMax());
	}

	// 分组
	@Test
	public void test5() {
		Map<Status, List<Employee>> map = emps.stream().collect(Collectors.groupingBy(Employee::getStatus));

		System.out.println(map);
	}

	// 多级分组
	@Test
	public void test6() {
		Map<Status, Map<String, List<Employee>>> map = emps.stream()
				.collect(Collectors.groupingBy(Employee::getStatus, Collectors.groupingBy((e) -> {
					if (e.getAge() >= 60)
						return "老年";
					else if (e.getAge() >= 35)
						return "中年";
					else
						return "成年";
				})));

		System.out.println(map);
	}

	// 分区
	@Test
	public void test7() {
		Map<Boolean, List<Employee>> map = emps.stream()
				.collect(Collectors.partitioningBy((e) -> e.getSalary() >= 5000));

		System.out.println(map);
	}

	//按照遇到的顺序连接由指定的分隔符分隔的输入元素。
	@Test
	public void test8() {
		String str = emps.stream().map(Employee::getName).collect(Collectors.joining(",", "----", "----"));
		System.out.println(str);
	}

	@Test
	public void test9() {
		Optional<Double> sum = emps.stream().map(Employee::getSalary).collect(Collectors.reducing(Double::sum));
		System.out.println(sum.get());
	}
}
